package service

import (
	"dsc-server/domain/req"
	"dsc-server/domain/resp"
	model2 "dsc-server/pkg/model"
	"fmt"
	"github.com/liangboceo/yuanboot/abstractions/xlog"
	"github.com/liangboceo/yuanboot/pkg/cache/redis"
	redisdb "github.com/liangboceo/yuanboot/pkg/datasources/redis"
	"time"
)

type CacheService struct {
	redisClient redis.IClient
	dbService   *DbService
	log         xlog.ILogger
}

func NewCacheService(redisDataSource *redisdb.RedisDataSource, service *DbService) *CacheService {
	conn, _, _ := redisDataSource.Open()
	client := conn.(redis.IClient)
	return &CacheService{redisClient: client, dbService: service, log: xlog.GetXLogger("CacheService")}
}

func (cache *CacheService) GetCache(req *req.CacheReq) string {
	defer func() {
		cacheViewHistory := model2.InstanceGetCacheViewHistory(req)
		err := cache.dbService.db.Create(cacheViewHistory).Error
		if err != nil {
			cache.log.Info("GetCache.error:%s", err)
		}

	}()
	key := fmt.Sprintf("%s:%s", req.ServerName, req.KeyName)
	json, _ := cache.redisClient.GetKVOps().GetString(key)
	cache.log.Info("GetCache.key:%s,value:%s", key, json)
	return json
}

func (cache *CacheService) SetCache(req *req.CacheSetReq) bool {
	defer func() {
		cacheViewHistory := model2.InstanceSetCacheViewHistory(req)
		err := cache.dbService.db.Create(cacheViewHistory).Error
		if err != nil {
			cache.log.Info("SetCache.error:%s", err)
		}
	}()
	key := fmt.Sprintf("%s:%s", req.ServerName, req.KeyName)
	cache.log.Info("SetCache.key:%s,value:%s", key, req.Value)
	err := cache.redisClient.GetKVOps().SetString(key, req.Value, time.Duration(req.Expire)*time.Second)
	if err != nil {
		cache.log.Info("SetCache.error:%s", err)
	}
	if err == nil {
		return true
	}
	return false
}

func (cache *CacheService) Lock(name string, timeOut int) bool {
	ops := cache.redisClient.GetLockOps()
	err, flag := ops.GetDLock(name, timeOut)
	if err != nil {
		return false
	}
	return flag
}
func (cache *CacheService) Unlock(name string) bool {
	ops := cache.redisClient.GetLockOps()
	err, flag := ops.DisposeLock(name)
	if err != nil {
		return false
	}
	return flag
}

// Info 获取详情
func (cache *CacheService) Info() (string, error) {
	return cache.redisClient.Info()
}

// GetKeys 获取redis keys
func (cache *CacheService) GetKeys(keysReq *req.KeysReq) (*resp.KeysResp, error) {
	result := &resp.KeysResp{BasePageResp: resp.BasePageResp{Page: keysReq.PageNum}}
	if keysReq.Keyword != "" {
		keysReq.Keyword = "*" + keysReq.Keyword + "*"
	}
	keys, total, err := cache.redisClient.ListKeys(uint64(keysReq.PageNum), keysReq.Keyword, int64(keysReq.PageSize))
	if err == nil {
		result.Total = int64(total)
		result.Data = make([]model2.Keys, len(keys))
		if len(keys) > 0 {
			for i, k := range keys {
				result.Data[i].KeyName = k
				t, e := cache.redisClient.GetExpire(k)
				if e == nil {
					if t.Seconds() < 0 {
						result.Data[i].Expire = time.Now().Add(time.Duration(1<<63 - 1)).String()
					} else {
						result.Data[i].Expire = time.Now().Add(time.Second * time.Duration(t.Seconds())).String()
					}
				}
			}
		}
	}
	return result, err
}

// GetKeyInfo 获取redis key详情
func (cache *CacheService) GetKeyInfo(keyInfoReq *req.KeyInfoReq) (*resp.KeyInfoResp, error) {
	result := &resp.KeyInfoResp{KeyName: keyInfoReq.Key}
	value, err := cache.redisClient.GetKVOps().GetString(keyInfoReq.Key)
	if err == nil {
		result.Value = value
		t, e := cache.redisClient.GetExpire(keyInfoReq.Key)
		if e == nil {
			result.Expire = t.Seconds()
		}
	}
	return result, err
}

// BatchDeleteKeys 批量删除redis keys
func (cache *CacheService) BatchDeleteKeys(keyDeleteReq *req.KeyDeleteReq) bool {
	flag := true
	for _, k := range keyDeleteReq.Keys {
		flag = cache.redisClient.Delete(k)
	}
	return flag
}

// SetKeyValue 设置key value
func (cache *CacheService) SetKeyValue(setKeysReq *req.SetKeysReq) (*resp.SetKeysResp, error) {
	result := &resp.SetKeysResp{KeyName: setKeysReq.KeyName, Value: setKeysReq.Value, Expire: setKeysReq.Expire}
	err := cache.redisClient.GetKVOps().Set(setKeysReq.KeyName, setKeysReq.Value, time.Duration(setKeysReq.Expire)*time.Second)
	return result, err
}
